#pragma once 

#include "Common.hpp"

const std::string Sep = "\r\n";
const std::string Blankline = Sep;
const std::string LineSep = " ";
const std::string HeaderLineSep = ": ";
const std::string defaulthomepage = "wwwroot";
const std::string http_version = "HTTP/1.0";
const std::string page404 = "wwwroot/404.html";
const std::string firstpage = "index.html";  // 首页

class HttpRequest
{
public:
    HttpRequest(){}

    // http 请求不需要序列化了，因为client是网页，会帮我们序列化
    // 反序列化还是要的

    // request_str:后面跟的都是 \r\n

    // GET /favicon.ico HTTP/1.1
    // Host: 114.132.95.87:8080
    // Connection: keep-alive
    // User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0
    // Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
    // Referer: http://114.132.95.87:8080/
    // Accept-Encoding: gzip, deflate
    // Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6

    bool IsHasArgs()
    {
        return _isexec;  // 如果有方法就会执行，执行了就会有参数
    }

    bool ParseHeaderKv()
    {
        for(auto& s : _req_header)
        {
            auto pos = s.find(HeaderLineSep);
            if(pos != std::string::npos) _headerkv[s.substr(0,pos)] = s.substr(pos+HeaderLineSep.size());
            else return false;
        }
        return true;
    }

    bool ParseHeader(std::string& request_str)
    {
        while(true)
        {
            std::string line;
            bool r = ParseOneLine(request_str, &line, Sep);
            if(r && !line.empty()) _req_header.push_back(line);
            else if(r && line.empty())
            {
                _blank_line = Sep;
                break;
            }
            else return false;
        }
        return true;
    }

    void Deserialization(std::string& request_str)
    {
        // 获取请求行
        if(ParseOneLine(request_str, &_req_line, Sep))
        {
            // 提取请求行中的详细字段
            ParseReqLine(_req_line, LineSep);
            ParseHeader(request_str);
            ParseHeaderKv();
            // 处理完后余下的就是正文部分
            _body = request_str;

            // 分析请求中，是否含有参数
            if(_method == "POST")
            {
                _isexec = true;
                _args = _body;
                _path = _uri;
            }
            else if(_method == "GET")
            {
                auto pos = _uri.find('?');
                if(pos != std::string::npos)
                {
                    // /login?username=zhangsan&passwd=123456
                    _path = _uri.substr(0,pos);
                    _args = _uri.substr(pos+1);
                    _isexec = true;
                }
            }
        }
    }

    // 获取文件内容
    std::string GetContent(const std::string path)
    {
        // 读取的时候要以二进制的形式打开，不然打开不了图片、视频、音频等文件
        std::string content;
        std::ifstream in(path, std::ios::binary);
        if(!in.is_open()) return "";
        in.seekg(0, in.end);  // 将读写位置定位到末尾
        int filesize = in.tellg();  // 文件的大小就是偏移量大小
        in.seekg(0, in.beg);  // 再定位回开头

        content.resize(filesize);
        in.read((char*)content.c_str(), filesize);

        in.close();



        // std::string content;
        // std::ifstream in(_uri);  // _uri 存储着文件资源的路径
        // if(!in.is_open()) return "";
        // // 读取成功
        // std::string line;
        // while(std::getline(in, line))
        //     content += line;
        // in.close();
        return content;
    }

    void Print()
    {
        std::cout << "method: " << _method << std::endl;
        std::cout << "uri: " << _uri << std::endl;
        std::cout << "version: " << _version << std::endl;
        for(auto& [k,v] : _headerkv)
            std::cout << k << " # " << v << std::endl;
        std::cout << "blank_line: " <<_blank_line << std::endl;
        std::cout << "body: " << _body << endl;
    }

    ~HttpRequest(){}

    std::string Uri()
    {
        return _uri;
    }

    std::string Path()
    {
        return _path;
    }

    std::string Args()
    {
        return _args;
    }

    void SetUri(const std::string uri)
    {
        _uri = uri;
    }

    // 获取文件后缀
    std::string Suffix()
    {
        // _uri -> wwwroot/index.html wwwroot/image/1.jpg wwwroot/login.html
        auto pos = _uri.rfind(".");
        if(pos == std::string::npos) return std::string(".html");
        else return _uri.substr(pos);
    }

private:
    // GET /favicon.ico HTTP/1.1   --->    // GET [sep] /favicon.ico [sep] HTTP/1.1
    void ParseReqLine(std::string& _req_line, const std::string sep)
    {
        (void)sep;
        std::stringstream ss(_req_line);
        ss >> _method >> _uri >> _version;
        // _uri = defaulthomepage + _uri;
    }

private:
    std::string _req_line;  // 请求行
    std::vector<std::string> _req_header;  // 请求报头
    std::string _blank_line;  // 空行
    std::string _body;  // 请求正文
    std::unordered_map<std::string, std::string> _headerkv;  // 请求报头的KV版

    // 在反序列化的过程中，细化我们解析出来的字段
    std::string _method;  // 请求方法
    std::string _uri;  // URI

    // 登录功能且用GET传参，会把账号密码传到uri上，所以分割路径和用户信息
    std::string _path;  
    std::string _args;

    std::string _version;  // HTTP版本

    bool _isexec = false;  // 是否需要执行
};





class HttpResponse
{
public:
    HttpResponse()
        :_version(http_version)
        ,_blank_line(Sep)
    {}

    // 构建应答
    void Bulid(HttpRequest &req)
    {
        // 定义Web根目录"/" 就是首页
        std::string uri = defaulthomepage + req.Uri();
        if(uri.back() == '/') uri += firstpage;
        req.SetUri(uri);

        _content = req.GetContent(uri);
        if(_content.empty())  
        {
            // 没有读取到东西 用户请求的资源不存在
            _status_code = 404;
            req.SetUri(page404);  // 将页面变成404页面
            _content = req.GetContent(page404);  // 重新获取
        }
        else
        {
            _status_code = 200;
        }
        _status_desc = CodeToDesc(_status_code);  

        if(!_content.empty()) SetHeader("Content-Length", std::to_string(_content.size()));

        std::string mime_type = SuffixToDesc(req.Suffix());
        SetHeader("Content-Type", mime_type);
        _body = _content;
    }

    // 序列化
    void Serialization(std::string* resp_str)
    {
        for(auto& [k,v] : _header_kv)
            _resp_header.push_back(k + HeaderLineSep + v);

        _resp_line = _version + LineSep + std::to_string(_status_code) + LineSep + _status_desc + Sep;

        // 序列化
        *resp_str = _resp_line;
        for(auto& line : _resp_header)
            *resp_str += line + Sep;
        *resp_str += _blank_line + _body;
    }

    void SetCode(int code)
    {
        _status_code = code;
        _status_desc = CodeToDesc(code);
    }

    void SetBody(const std::string &body)
    {
        _body = body;
    }

    // 想要什么属性往里面加
    void SetHeader(const std::string &k, const std::string &v)
    {
        _header_kv[k] = v;
    }

    ~HttpResponse(){}
private:
    // 状态码和状态描述是强相关的
    std::string CodeToDesc(int code)
    {
        switch (code)
        {
            case 200:
                return "OK";
            case 404:
                return "Not Found";
            case 302:  // 登录成功后，跳转到首页
                return "Found";
            default:
                break;
        }
        return "";
    }

    std::string SuffixToDesc(const std::string &suffix)
    {
        if(suffix == ".html")
            return "text/html";
        else if(suffix == ".jpg")
            return "application/x-jpg";
        else
            return "text/html";
    }

private:
    // 必备的要素
    std::string _version;  // 版本
    int _status_code;  // 状态码
    std::string _status_desc;  // 状态码描述

    std::string _content;  // 将来要给用户返回的内容

    std::string _resp_line;  // 状态行
    std::vector<std::string> _resp_header;  // 响应报头
    std::string _blank_line;  // 空行
    std::string _body;  // 响应正文
    std::unordered_map<std::string,std::string> _header_kv;  
};